#pragma once
#include <ntddk.h>

#define DECLARE_SINGLE_INSTANCE(ClassName) private:static ClassName* _instance;public:static ClassName* Instance();	\
	public:static void Unload(){if(_instance){delete _instance;_instance = NULL;}}	\
	private:DECLARE_SUPPORT_ALLOCATOR_WITH_STATIC_DEFAULT(ClassName)
#define IMPLEMENT_SINGLE_INSTANCE(ClassName) ClassName* ClassName::_instance = NULL;ClassName* ClassName::Instance(){if(!_instance)_instance = new ClassName();return _instance;} \
	IMPLEMENT_SUPPORT_ALLOCATOR_WITH_STATIC_DEFAULT(ClassName)

#define DELCARE_SUPPORT_ALLOCATOR static void* operator new(size_t regSize, Allocator* allocator);	\
	static void operator delete(void* ptr);

#define IMPLEMENT_SUPPORT_ALLOCATOR(ClassName) void* ClassName::operator new(size_t size, Allocator* allocator){if(size == 0)size = 1;return allocator->Alloc(size);} \
	void ClassName::operator delete(void* ptr){if(ptr == NULL)return;void* regisonStart = ((char*)ptr) - sizeof(Allocator*);Allocator* allocator = *((Allocator**)regisonStart);return allocator->Free(regisonStart);}

#define DECLARE_SUPPORT_ALLOCATOR_WITH_STATIC_DEFAULT(ClassName) private:	\
	static void* operator new(size_t regSize);	\
	DELCARE_SUPPORT_ALLOCATOR;
#define IMPLEMENT_SUPPORT_ALLOCATOR_WITH_STATIC_DEFAULT(ClassName) 	static char _instanceStub[sizeof(ClassName) + StaticAllocator::StubSize];\
	void* ClassName::operator new(size_t regSize){return StaticAllocator(_instanceStub, sizeof(_instanceStub)).Alloc(regSize);}	\
	IMPLEMENT_SUPPORT_ALLOCATOR(ClassName)

class Allocator
{
public:
	virtual void* Alloc(ULONG size) = 0;
	virtual void Free(void* ptr) = 0;
};


class DynamicAllocator : public Allocator
{
	static DynamicAllocator* _instance;
	DynamicAllocator();
	DELCARE_SUPPORT_ALLOCATOR
public:
	static DynamicAllocator* Instance(void);
	void* Alloc(ULONG size);
	void Free(void* ptr);
};

class DynamicNPAllocator : public Allocator
{
	static DynamicNPAllocator* _instance;
	DynamicNPAllocator();
	DELCARE_SUPPORT_ALLOCATOR
public:
	static DynamicNPAllocator* Instance(void);
	void* Alloc(ULONG size);
	void Free(void* ptr);
};


class StaticAllocator : public Allocator
{
	void* ptr;
	unsigned regSize;
	void* operator new(unsigned size);
public:
	StaticAllocator();
	static const unsigned StubSize = sizeof(StaticAllocator*);
	StaticAllocator(void* pStaticRegion);
	StaticAllocator(void* pStaticRegion, unsigned regionSize);
	void* Alloc(ULONG size);
	void Free(void* ptr);
};